NativeJ Version 4.5.7

What is NativeJ?

NativeJ is a Java EXE maker. The executable generated by NativeJ is uniquely customized to launch your Java application under Windows. NativeJ is not a compiler! Think of NativeJ-generated executables as supercharged "binary batch files", with the following benefits:

  • Custom icon. Each executable is represented by a unique icon, just like native apps.

  • Native behaviour. When the user double-clicks on the EXE to run your application, there won't be an annoying console window popping up briefly.

  • Faster startup. Executing a batch file involves a great deal of overhead, including loading the command processor and parsing the batch file. The native EXE loads the JVM directly, resulting in snappier program startup.

  • Native splash screen. Display a splash screen of your choice immediately upon startup while your application loads.

  • Unique process name. When viewed in the task list, the user sees tomcat.exe, or jedit.exe, instead of the nondescript java.exe, or javaw.exe. This is particularly important for personal firewall programs, which depend on unique process names to trigger the appropriate filter rules.

  • Install as service. NativeJ generates executables that can be installed as a Win32 service natively, with the ability to specify dependencies.

If you can write a batch file, you can use NativeJ! Use the project wizard to create a custom executable that works just for your application. No need to write custom JNI code, or wrestle with a C compiler. Just click-and-go! It's that easy!

NativeJ has already been proven to work with many complex and non-trivial open-source applications. You can find a partial list here. In short, you will find NativeJ an extremely versatile tool for distributing your Java applications professionally.

NativeJ is available in two versions:

  • Standard Edition. The following features are not available in the standard edition: Win32 service creation, JAR files embedding, customization of strings and messages.

  • Professional Edition. All features are available in the professional edition, including: Win32 service creation, JAR files embedding, customization of strings and messages.


Features

  • Simple point-and-click interface. No need to wrestle with C compiler and JNI code.

  • Project wizard to simplify the process of creating new projects.

  • Generates console and graphical EXE, as well as Win32 service.

  • Ability to configure custom process icon, name and priority.

  • Ability to configure service name, description, startup type, characteristics and dependencies.

  • Ability to configure application working directory.

  • Ability to use application parameters from a configuration file when the executable is run.

  • Automatic detection of JRE/JDK (client or server) on target machine.

  • Support for private bundled JRE.

  • Ability to specify search order for JRE/JDK on target machine.

  • Dynamic classpath construction by automatically appending all JAR and ZIP files in classpath directories to the final classpath.

  • Ability to embed application JAR files into generated EXE.

  • Native splash screen that pops up as soon as the EXE is activated, while your application loads in the background. Splash screen can be configured to stay on the screen for a fixed number of seconds, or automatically removed as soon as the Java application displays a window.

  • Ability to restrict graphical applications to a single instance.

  • Ability to redirect stdout/stderr to external log files or popup message box.

  • Ability to customize/localize strings and messages in the generated EXE.

  • Command-line generator for integration with build tools.

  • Supports Sun JRE 1.2 and above, as well as IBM JRE 1.2 and above.


System Requirements

  • Windows NT/2000/XP is required for running NativeJ.
    * Executables generated by NativeJ will run on all versions of Windows, including Windows 9x/ME.

  • Java Runtime Environment (JRE) 1.2 and above.


Frequently asked questions

Does NativeJ compile my Java application into native code?

No, NativeJ generates a Win32 EXE that will launch your Java application using the JVM. You will still need to include your application class or jar files. Think of these as DLLs or COM objects that are included with many native applications.

Help! The generated EXE does not seem to include the JRE.

The generated EXE does not include the JRE. You will still need to bundle the JRE files (about 20MB compressed) with your application. If space is a major consideration, you may want to think about providing a link to the JRE and asking the users to download/install the JRE themselves.

Do I need to regenerate the EXE every time I recompile my Java application?

No, you do not have to as long as the main class file and various project parameters remain the same. Think of the NativeJ executable as a binary version of your batch file. You do not need to rewrite the batch file every time you recompile your application!

Does NativeJ work with code obfuscater products on the market?

Yes. As long as the final class or jar files can be launched by the JVM, the NativeJ-generated executable will work correctly.

Does NativeJ work if my application uses custom DLLs that I call through JNI (Java Native Interface)?

Yes, NativeJ EXE will work seamlessly with your custom DLLs.

I am trying to make NativeJ load MyApp.class, but I can't seem to do so. How do I add MyApp.class to the CLASSPATH?

Typically, you should package MyApp.class into a jar file, and add the jar file to the CLASSPATH. You can find more information about creating jar files here. However, if for some reason you only wish to use the class file, you can add a single period "." to the CLASSPATH, in which case NativeJ will look for class files under the same directory as the EXE.

I am trying to run a NativeJ-generated EXE on a particular machine, but I keep getting ""Unable to locate suitable Java Runtime Environment on this machine." What is wrong?

This typically means the JRE is not installed correctly on the target machine. A machine with a properly installed JRE should have the following keys in the Windows registry: HKLM\SOFTWARE\JavaSoft\Java Runtime Environment\CurrentVersion contains the current version of JRE (eg. "1.4"); HKLM\SOFTWARE\JavaSoft\Java Runtime Environment\<version>\RuntimeLib contains the full path to JVM.DLL (eg. C:\Program Files\Java\j2re1.4.1_03\bin\client\jvm.dll).

Is it possible to use a non-BMP image for the splash screen? BMP files tend to be very large sized - which causes serious download performances to our application.

Currently, we are only able to handle native Windows resource types. That means BMP only, not JPG or GIF. You can try decreasing the BMP size by reducing the color depth from 24-bit to 8-bit. This should reduce the size of the image substantially.

If I use NativeJ as part of our installation for our customers, would I have to purchase it for each installation, or only purchase it one time?

You do not need to pay any licensing fee for the executables generated and deployed at customers' sites. However, if you have 10 developers and all of them wish to run NativeJ on their own machine, then you will need to pay for 10 licenses.

Does NativeJ enable my application to receive files dragged and dropped from Windows explorer?

No, this has to be done within the Java application. A good example is available at http://thecodeproject.com/java/dnd.asp, and there are numerous code samples available throughout the web.

Does NativeJ enable my application to register file type associations so that my application can be started by double-clicking on a document icon?

No, this can either be done from within the installer program eg. InstallShield, or from within the Java application itself. For the latter option, you will need to write some JNI code, or use a JNI library such as WinPack.

Does NativeJ compile my Java application into native code?

No, NativeJ generates a Win32 EXE that will launch your Java application using the JVM. You will still need to include your application class or jar files. Think of these as DLLs or COM objects that are included with many native applications.

How does NativeJ recognize that an instance of a program is already running and refuse to start another instance?

NativeJ uses the name of the main application class eg. com.abc.MyApp as a unique identifier and refuse to start another instance of a program which uses the same class.

I am using the same class for two separate applications. How do I get NativeJ to see them as different applications?

This is not possible. The best way to resolve this is to write a small wrapper class that calls the main() method of the original application, and use that in your second NativeJ application instead.

I am using nativejc with Ant, and I get the error message: "The process cannot access the file because it is being used by another process". What is wrong?

This error occurs because you are embedding JAR files into the executable, and one or more of those JAR files are locked by Ant (actually the particular instance of java.exe running Ant), hence they cannot be accessed by nativejc. To fix this problem, make sure that none of the JAR files targeted for embedding are listed in the classpath.

How do I find out the full path and filename of the NativeJ executable from within my Java code?

Starting from Ver 4.5.2, the full path and filename of the NativeJ executable are exposed in the nativej.exe.path property. You can read its value from within your Java code using System.getProperty("nativej.exe.path") from within your Java code.

I am using NativeJ to create a Win32 service. Every time I change the project configuration and regenerate the executable, I get an error message saying that the file is locked. What's wrong?

You need to stop the service before regenerating, because otherwise the executable will still be running in memory and cannot be overwritten.

I am passing a system environment variable myenv to a Win32 service via -Dmyprop=%myenv% in the JVM options. Why is the value of myprop blank when read in the Win32 service?

Environment variables are not refreshed for Win32 services until the machine is rebooted. This is by Windows' design, and applies to all Win32 services, not just NativeJ-generated ones. Hence, whenever you add or update a system environment variable for a Win32 service, you need to reboot the machine in order for the new value to take effect.


Executable

The following parameters apply to the target executable:

  • Application type. Choose Console for console apps, or Graphical for GUI apps.

  • Allow application to be installed as service? If Yes, the executable will function as a Win32 service.

  • Executable filename. The filename of the executable to be generated. This will also appear as the process name of the application in the Task Manager (up to 15 characters). This field is required.

  • Executable icon. The filename of the icon which will be used for the generated executable. This file must be in ICO format. If specified correctly, the icon should display in the preview box. This field is optional. If left blank, the default Java icon will be used.

  • Redirect System.out to. Choose None, File, or Popup message box/Event log. If None is selected, System.out will not be redirected. If File is selected, all output to System.out will be captured to the given log file. If Popup message box/Event log is selected, all output to System.out will be displayed in a popup message box (for GUI app), or the event log (for Windows services) only if the JVM aborts on fatal error.

  • Redirect System.err to. Choose None, File, or Popup message box/Event log. If None is selected, System.err will not be redirected. If File is selected, all output to System.err will be captured to the given log file. If Popup message box/Event log is selected, all output to System.err will be displayed in a popup message box (for GUI app), or the event log (for Win32 services) only if the JVM aborts on fatal error.

  • Initial process priority. Indicate the initial process priority when the executable is run. The default process priority is Normal.


Java Runtime

The following parameters apply to the Java runtime used by the executable:

  • Baseline version. This indicates the baseline JRE version required by the application. For example, if the JRE installed on the target machine is 1.2, but the minimum version required is 1.3, then the executable will display an error message and exit. This argument only applies if JVM DLL is left blank i.e. if you did not bundle a specific JRE with your application.

  • JVM DLL. When this parameter is left blank, the executable will automatically look for a suitable JRE on the target system. However if you are bundling a specific JRE with your application, you can specify the relative path to the JVM DLL eg. jre\bin\hotspot\jvm.dll. Multiple JVM DLLs can be specified by delimiting the pathnames with semi-colons.

  • JVM search order. By default, the executable will use the private JRE if one is available. Otherwise, it will search for a suitable Java Runtime Environment (JRE) on the target machine. If that fails, then it will search for a suitable Java Developer Kit (JDK). You can change the order of search, as well as restricting the search to only the JRE or JDK.

    Please refer to How NativeJ searches for a suitable JDK/JRE for more information on this topic.

  • JVM options. The options to pass to the JVM. You should only pass the ‑X or ‑D options to the JVM eg. ‑Xms64m ‑Xmx128m. Note that some ‑X options are JVM version-dependent. For more information, refer to Passing options to the Java runtime.

  • Classpath. Specify the classpath required by the application. Multiple entries are delimited by semi-colon. Each entry in the classpath could be a JAR or ZIP file. If the entry is a directory, all the JAR and ZIP files in that directory will be dynamically appended to the final classpath at runtime. This operation is recursive, hence all subdirectories will also be searched for JAR or ZIP files.

    If you are bundling a specific JRE with your application, there is another way to specify the class files required by your application. For more information, refer to An alternative approach to classpath.

    This field is required.

  • Embedded JAR files Specify the JAR or ZIP files you wish to embed into the final executable. When the executable is run for the first time, these JAR files will be extracted into a temporary directory and appended to the classpath. Subsequently, as long as the JAR files are not modified or removed, the extraction step will be skipped. Note that this could increase the size of the final executable tremendously, depending on the total size of the embedded JAR files.

    Please refer to JAR files embedding for more information on this topic.

  • Delete JAR files when EXE terminates Normally, embedded JAR files are not deleted once they are extracted into a temporary directory. This enhances startup speed because the extraction step will be skipped when the application is run the next time. However, if you want the embedded JAR files to be removed when the executable terminates, select this checkbox.

Environment variable substitution

Before the JVM options and classpath values are passed to the runtime, a final substitution is made where all tokens of the form %name% are replaced with the value of the equivalent environment variable. For example, if the classpath contains myapp.jar;%CLASSPATH%, and the CLASSPATH environment variable on the target machine contains mydriver1.jar;mydriver2.jar, then the final classpath will contain myapp.jar;mydriver1.jar;mydriver2.jar after substitution.

A special case is %JAVA_HOME% (case-sensitive), which will always be substituted for the actual base directory of the JDK/JRE that is found on the target machine. For example, if the classpath contains %JAVA_HOME%\lib\tools.jar, and a suitable JDK is found in C:\j2sdk1.4.1_02, then the final classpath will contain C:\j2sdk1.4.1_02\lib\tools.jar after substitution.


Application

The following parameters apply to the Java application:

  • Main application class. The name of the Java class which is the application entry point. This class must have a main() method. This field is required.

  • Default application arguments. The default arguments to pass to main(). These arguments will be replaced by arguments entered directly from the command-line, if any.

  • Working directory. The default working directory is the directory where the EXE resides. This parameter allows you to change the working directory. For example, if your program creates a log file, that log file will be created in the working directory.

  • Use current directory. If you select this option, the working directory will be set to the current directory. For example, if the EXE resides in C:\Program Files\MyApp, but the user starts the EXE in C:\My Documents, then the working directory is C:\My Documents. This is useful for applications which must process files in the current directory eg. a utility that automatically creates thumbnails for all JPEG files in the current directory.

  • Set runtime and classpath relative to working directory. By default, the working directory does not affect the runtime and classpath i.e. the JVM DLL and the classpath will still be relative to the EXE directory, even if the working directory is changed. However, setting this option will cause the runtime and classpath to be relative to the working directory instead.

  • Application configuration file. This allows you to specify the filename of a configuration file from which parameters will be read when the executable is run. The configuration file has the following format:

    [Application Configuration]
JvmOptions = -Xmx8m -Xmx32m
    This allows you to modify the runtime characteristics of your program without regenerating the executable. Currently, two parameters are supported:

    JvmOptions | Options to pass to the JVM.
    AppOptions | Arguments to pass to the Java application.

    If you are not using a configuration file, simply leave the field blank.

    Note that the configuration file should always be located in the same directory as the executable file, regardless of the working directory setting.

  • Allow multiple instances of the application? Applies to GUI applications only. Specifies whether to allow multiple instances of the sample application. If Yes, the executable will display an error message on startup if it detects that another instance of itself is already running in the system.


Service

The following parameters applies only if you are creating a Win32 service:

  • Service name. The service name which appears in Services when installed. This field is required.

  • Startup type. Whether the startup type of the service is automatic or manual.

  • Allow service to interact with desktop. Whether the service is allowed to interact with the desktop of the current user.

  • Service description. The service description which appears in Services when installed.

  • Install command. Command used to install the service. By default, this is ‑install.

  • Uninstall command. Command used to uninstall the service. By default, this is ‑uninstall.

  • Start argument(s). The argument(s) to pass to the main() method when starting the program in service mode.

  • Stop argument(s). The argument(s) to pass to the main() method when stopping the program in service mode.

  • Call System.exit() to stop service. Instead of calling main() to stop the service, call System.exit() instead. Any termination logic that the program registers via Runtime.addShutdownHook() will be called before the JVM terminates.

  • Service dependencies. Enter a list of services that this service is dependent on. Multiple entries are delimited by semi-colon. When the service is installed, this information will be written into the system. Leave this field blank if the service is not dependent on other services.


Splash Screen

The following parameters applies only if you are defining a native splash screen for a GUI application:

  • Splash screen title. This is the title of the splash screen icon which appears in the task bar when the splash screen is displayed. It should contain something meaningful such as "Loading <application name>..".

  • Bitmap file. This is the bitmap file to be used for the splash screen. The file must be in BMP format. It should have a nice thick or 3D border to make it stand out from the screen. The resolution for the bitmap should be less than 640x480 (for maximum compatibility with different screen resolutions). If specified correctly, the bitmap should display in the preview box.

  • How long should the splash screen be displayed? You can choose to display the splash screen for a fixed number of seconds, or have the splash screen removed as soon as the Java application displays its first window.


Messages

You may customize the list of internal messages used by the executable. For example, you may create localized versions of these messages for different countries/locales.

Note that some messages are parameterized. For example, the message "Service install: %s" is displayed when a Win32 service executable is installed and contains one parameter, referenced by %s. When customizing these messages, please ensure that the parameters are retained, otherwise the messages may become unintelligible.

Customization of messages are project-specific. If you need to reuse customized messages, the best way is to open a previous project containing the customized messages, and invoke File... Save Project As... to save the customized messages to another project file.


Generating a console executable

Note: The following tutorial assumes you have the Java Runtime Environment (1.2 and above) installed on your machine.

In this tutorial, we are going to learn how to generate a console executable. The Java program that we are going to create an executable for is a simple "Hello, World" program. This program is called Console.java, and can be found in the examples-source\ subdirectory.

File: Console.java
1:  package examples;
2:
3:  public class Console
4:  {
5:      public static void main(String[] args) throws Exception
6:      {
7:          if (args.length == 0)
8:              System.out.println("Hello World!");
9:          else
10:             System.out.println("Hello " + args[0] + "!");
11:     }
12: }

This simple program prints out "Hello, World!" when run without any parameters.

C:\Program Files\NativeJ> java examples.Console
Hello, World!

However, when supplied with a name as a parameter, it will print out "Hello, <name>!".

C:\Program Files\NativeJ> java examples.Console John
Hello, John!

Let's see how we can create an executable called console.exe, which will run the examples.Console program.

The Console.java file has been compiled and packaged in examples\examples.jar, along with the other examples. In this subdirectory, you will also find console.njp, along with other .njp files.

Run NativeJ. Then, click on File... Open... and open executables\console.njp. This is the project file for examples.Console, and it has the following parameters:

Name | Value | Remarks
Main
Application type | Console | The executable generated will run as a console program.
Executable icon | console.ico | The application icon.
Executable filename | console.exe | The filename of the generated executable.
Java Runtime
Classpath | examples.jar | This contains required class files i.e. examples.Console.
Application
Main application class | examples.Console | The name of the Java class we wish to run. This class should have a main() method.

Now, click on File... Generate... to generate the executable. If everything goes well, you will receive a notification that console.exe has been generated.

Run console.exe without any parameters:

C:\Program Files\NativeJ\executables> console
Hello, World!

Now, run console.exe with a name:

C:\Program Files\NativeJ\executables> console John
Hello, John!

You can also supply some default arguments to examples.Console. Enter John in Default arguments, then generate the executable again. Now, run console.exe without any parameters:

C:\Program Files\NativeJ\executables> console
Hello, John!

Run console.exe with another name besides John:

C:\Program Files\NativeJ\executables> console Mary
Hello, Mary!

As you can see, the executable will use the default arguments if none are available. If the user supplies the arguments, then these are used instead of the default.

In this tutorial, the JVM DLL parameter is left blank so that when console.exe is run, it will automatically detect and load a suitable JVM (in this case, any JVM version >= 1.2) on the target system. You can also bundle a specific JVM with your application and force the executable to use that JVM. To find out how, please refer to Bundling a Particular Java Runtime.


Generating a graphical executable

In this tutorial, we are going to learn how to generate a graphical executable i.e. a native executable that behaves like a Win32 GUI program.

The Java program that we are going to create an executable for is a simple "Hello, World" type AWT program. This program is called Gui.java, and can be found in the examples-source\ subdirectory.

File: Gui.java
1:  package examples;
2:
3:  import java.awt.*;
4:  import java.awt.event.*;
5:
6:  public class Gui
7:  {
8:      public static void main(String[] args)
9:      {
10:         // Create the main window and components used by this app
11:         Frame frame = new Frame("Gui");
12:         String msg = "Hello World!";
13:         if (args.length > 0) msg = "Hello " + args[0] + "!";
14:         Label label = new Label(msg, Label.CENTER);
15:
16:         // Handle the exit event for the main window
17:         frame.addWindowListener(new WindowAdapter()
18:         {
19:             public void windowClosing(WindowEvent e)
20:             {
21:                 System.exit(0);
22:             }
23:         });
24:
25:         // Position the components within the main window
26:         frame.setLayout(new BorderLayout());
27:         frame.add(label, BorderLayout.CENTER);
28:
29:         // Resize and show main window
30:         frame.pack();
31:         frame.setSize(320, 240);
32:         frame.show();
33:     }
34: }

When run without any parameters, this program displays a "Hello, World!" message. When run with a name as the parameter eg. java examples.Gui John, it will display "Hello, <name>!" instead.

Let's see how we can create an executable called gui.exe, which will run the examples.Gui program.

The Gui.java file has been compiled and packaged in examples\examples.jar, along with the other examples. In this subdirectory, you will also find gui.njp, along with other .njp files.

Run NativeJ and open the gui.njp project. Confirm that it defines the following parameters:

Name | Value | Remarks
Main
Application type | Graphical | The executable generated will run as a GUI program.
Executable icon | gui.ico | The application icon.
Executable filename | gui.exe | The filename of the generated executable.
Java Runtime
Classpath | examples.jar | This contains required class files i.e. examples.Gui.
Application
Main application class | examples.Gui | The name of the Java class we wish to run. This class should have a main() method.

Now, click on File... Generate... to generate the executable. If everything goes well, you will receive a notification that gui.exe has been generated.

Run gui.exe without any parameters, and with the name John. You should observe the same output as when running the program using java.

Now, run gui.exe twice without quitting. You should get the following error:

If you select Yes to Allow multiple instances and generate gui.exe again, you should be able to start multiple instances of gui.exe without any errors.


Generating a Win32 service executable

In this tutorial, we are going to learn how to generate a service executable i.e. an executable that could be installed as a service and started/stopped using the Services control panel applet. Noted that services are only available on Windows NT/2K/XP, and not on the Win9x/ME platforms.

The Java program that we are going to use is a simple console program that continually logs the date/time to a file called service.log at 5 seconds interval. The main() method takes a ‑start argument to start the logging activity, and a ‑stop argument to stop the logging.

File: Service.java
1:  package examples;
2:
3:  import java.io.*;
4:  import java.util.*;
5:
6:  public class Service
7:  {
8:      static boolean stop = false;
9:      public static void main(String[] args) throws Exception
10:     {
11:         // Start the service
12:         if (args[0].equals("-start"))
13:         {
14:             while(true)
15:             {
16:                 // Append current date/time to log file
17:                 log("Current date/time is " + new Date());
18:
19:                 // Sleep for 5 secs
20:                 Thread.currentThread().sleep(5000);
21:
22:                 // Check for termination
23:                 if (stop)
24:                 {
25:                     log("Service stopped.");
26:                     break;
27:                 }
28:             }
29:         }
30:         else
31:         // Stop the service
32:         if (args[0].equals("-stop"))
33:         {
34:             // Set the termination flag
35:             stop = true;
36:         }
37:     }
38:
39:     /**
40:      * Log given string to file "service.log".
41:      */
42:     static void log(String msg) throws IOException
43:     {
44:         PrintWriter pw = new PrintWriter(
45:             new FileWriter("service.log", true));
46:         pw.println(msg);
47:         pw.close();
48:     }
49: }

Let's generate an executable called service.exe, which will run our examples.Service program.

The Service.java file has been compiled and packaged in examples\examples.jar, along with the other examples. In this subdirectory, you will also find service.njp, along with other .njp files.

Run NativeJ and open the service.njp project. The project defines the following parameters:

Name | Value | Remarks
Main
Application type | Console | The executable generated will run as a console program.
Allow as service | Yes | The executable generated will run as a Win32 service.
Executable icon | services.ico | The application icon.
Executable filename | services.exe | The filename of the generated executable.
Java Runtime
Classpath | examples.jar | This contains required class files i.e. examples.Service.
Console
Main application class | examples.Service | The name of the Java class we wish to run. This class should have a main() method.
Default application arguments | -start | The argument(s) to pass to the main() method when program is started normally.
Service
Service name | Test Service | The service name which will appear in Services when installed.
Install command | ‑install | The command line argument to install the service. By default, this is ‑install.
Uninstall command | ‑uninstall | The command line argument to uninstall the service. By default, this is ‑uninstall.
Start argument(s) | ‑start | The argument(s) to pass to the main() method when starting the program.
Stop argument(s) | ‑stop | The argument(s) to pass to the main() method when stopping the program.

Now, click on File... Generate... to generate the executable. If everything goes well, you will receive a notification that service.exe has been generated.

Now use service ‑install to install the service. You should see the following message:

C:\Program Files\NativeJ\executables>service ‑install
Service installed: Test Service

Check the services list using the Services control panel applet. You should see a new entry called Test Service.

Now start Test Service using Services. You should find a file called service.log written to the same directory where services.exe resides. The file contains the date/time logged approximately every 5 seconds.

Current date/time is Sat Jun 01 22:20:04 GMT+08:00 2002
Current date/time is Sat Jun 01 22:20:09 GMT+08:00 2002
Current date/time is Sat Jun 01 22:20:14 GMT+08:00 2002
Current date/time is Sat Jun 01 22:20:19 GMT+08:00 2002
Current date/time is Sat Jun 01 22:20:24 GMT+08:00 2002

Now, stop the service. The last line of service.log should contain the words "Service stopped.", logged by line 25 of Service.java.

If you encounter any errors while starting or stopping the service, launch Event Viewer and look under Application Log for messages attributed to Test Service.

Use service ‑uninstall to uninstall Test Service.

If you run examples.Service directly using java examples.Service ‑start, you won't be able to stop it using java examples.Service ‑stop. That's because they will be running under two different JVM instances, which means the stop flag set to true in line 35 of Service.java will not be reflected in the first JVM instance. The NativeJ-generated executable has no problems with this approach because it actually calls main() with the ‑stop argument through a separate thread within the same JVM instance, but you won't be able to do so when running using java or javaw.

If you wish to implement a start/stop mechanism that is generic and works under java/javaw (in fact, across all Java-enabled platforms), please refer to Implementing a Generic Start/Stop Mechanism.


Generating an executable for Tomcat

In this tutorial, we are going to generate an executable for Tomcat. Tomcat is an open-source reference servlet container developed by the Apache Group. It is widely used and is chosen as an example to show how easy it is to generate a executable for a non-trivial Java application.

Since Tomcat is rather large and is constantly being improved, we chose not to bundle it with NativeJ. Instead, you can download the latest source/binary builds from http://jakarta.apache.org/tomcat/index.html. This example applies to Tomcat 4.1.x, though it can be easily adopted for other versions of Tomcat.

The downloaded binary distribution should be in the form tomcat-4.1.x.zip. Unzip it into the examples\ subdirectory. The base directory is jakata-tomcat-4.1.x\. For simplicity, rename it to tomcat\. When you are done, the directory structure should look like this:

C:\
  Program Files\
    NativeJ\
      executables\
        tomcat\

Now let's test if Tomcat is working properly.

> cd C:\Program Files\NativeJ\executables\tomcat
> set JAVA_HOME=C:\JDK
> set CATALINA_HOME=C:\Program Files\NativeJ\executables\tomcat
> bin\startup.bat

If all goes well, a separate command window will pop up:

You should now be able to access the Tomcat homepage at http://localhost:8080/.

Use bin/shutdown.bat to stop Tomcat.

Now, launch NativeJ, and populate the new project with the following parameters:

Name Value Remarks
Main
Application type
Console
The executable generated will run as a console program.
Allow as service
Yes
The executable generated will run as a Win32 service.
Executable icon
tomcat.ico
The application icon.
Executable filename
tomcat.exe
The filename of the generated executable.
Java Runtime
Classpath
bin;
server\lib;
common\lib;
%JAVA_HOME%\lib\tools.jar
This contains required .jar files. In this case, only the directories containing the required .jar files are specified. The executable is smarted enough to dynamically generate the classpath at runtime which includes all the .jar files in these directories.
Application
Main application class
org.apache.catalina.startup.Bootstrap
The name of the Java class we wish to run. This class should have a main() method.
Service
Service name
Tomcat
The service name which will appear in Services when installed.
Install command
‑install
Command used to install the service. By default, this is ‑install.
Uninstall command
‑uninstall
Command used to uninstall the service. By default, this is ‑uninstall.
Start argument(s)
start
The argument(s) to pass to the main() method when starting the program.
Stop argument(s)
stop
The argument(s) to pass to the main() method when stopping the program.

Now, click on File... Generate... to generate the executable. If everything goes well, you will receive a notification that tomcat.exe has been generated.

The Tomcat executable can function both as a console program, as well as a Win32 service.

To start Tomcat from the command line, type:

C:\Program Files\NativeJ\executables\tomcat> tomcat start

To stop Tomcat from the command line, type:

C:\Program Files\NativeJ\executables\tomcat> tomcat stop

To install Tomcat as a service, type:

C:\Program Files\NativeJ\executables> tomcat ‑install
Service installed: Tomcat

To uninstall the Tomcat service, type:

C:\Program Files\NativeJ\executables> tomcat ‑uninstall
Service uninstalled: Tomcat

Note that to execute JSP scripts, you must either have the JDK installed on the target system, or you need to copy the \jdk\lib\tools.jar file to lib\ext in the JRE installation directory. That's because by default the JRE does not contain the compiler class com.sun.tools.javac.Main. But executing JSP scripts require the Java compiler class to be present, so you will need to copy the tools.jar file to the JRE lib\ext subdirectory, which is reserved for extension libraries.


Using the command-line version of NativeJ

Under most situations, there is no need to regenerate the executable as long as your project parameters remain the same. However, certain projects mandates the generation of executables during the build process and prohibit the check-in of EXE files .

We have included a command-line version of NativeJ called nativejc.exe for interfacing with the build process. It takes the project filename as its only parameter, loads the project file, generates the executable, then exits immediately.

Usage: nativejc [-v] <project>

The optional switch -v turns on verbose mode so that more messages are displayed during EXE generation. This may be useful for diagnostic purposes.

Note that if you are using a Java-based build tool such as Ant, make sure that the JAR files you wish to embed into the executable are not located in the classpath. Otherwise, when Ant executes, the instance of java.exe running it will lock all the JAR files in the classpath. Then NativeJ won't be able to access them and will abort with an error.


Bundling a private Java runtime

When you leave the JVM DLL parameter blank, the generated executable will detect and use the the first JRE installed on the target machine which meets the JVM version requirement.

It is also possible for you to bundle a private JRE with your application, and generate an executable that uses the bundled JRE regardless of other runtimes installed on the target machine.

There are a few advantages to bundling a private JRE with your application.

  • Since you can never be sure which make and version of JRE is installed on the target machine (if indeed one is installed at all), the safest bet is to bundle your own JRE so that you can be certain the application will work flawlessly, since you have ultimate control of which make or version of JRE to bundle with your application.

  • If the user does not already have a JRE installed on the target machine, bundling a JRE spares him the inconvenience of downloading a JRE himself. This is especially true if the user may not have broadband access to the Internet.

  • You can also choose to include the JRE installer with your distribution. However, this requires the user to run another installer, which may pose an inconvenience. You can, of course, choose to run the JRE installer automatically within your application installer by detecting if a JRE is already present on the target machine. However this makes the installer more complex. The installer needs to detect whether a JRE is already available on the target system, whether the make and version is up to the mark, and whether it is alright to overwrite the current JRE etc.

  • You may also be forced to bundle a JRE with your application if it depends on an older JRE (or a specific make/version of a JRE) to work. Since there is always the possibility that the user already has the latest JRE installed on his machine, it will be unacceptable to expect him to replace his JRE with an older version just so that he can run your application.

The primary concern with bundling your own JRE is the footprint of your application. Bundling your own JRE potentially increases your distribution and installation footprint by tens of megabytes. If the application needs to be delivered via the Internet, or the target system has diskspace constraints, then bundling your own JRE may not be acceptable.

The decision of whether to bundle or not to bundle your own JRE depends on the factors mentioned above. However, if you do choose to bundle your own JRE, it is very simple to do so with NativeJ.

Let's say we decide to bundle a private JRE for our first example program, examples.Console. Originally, the application directory contains only the executable console.exe and examples.jar.

approot\
  console.exe
  examples.jar

Let's copy an existing JRE installed on your machine to your application directory. The application directory should now look like:

approot\
  jre\
    bin\
      client\
        jvm.dll
      ..
      (other files such as java.dll and awt.dll etc.)
    lib\
      ..
      (other files such as charsets.jar and rt.jar etc.)
  console.exe
  examples.jar

The jvm.dll under jre\bin\client\ (in some JREs, they are located under jre\bin\classic\, jre\bin\hotspot\ or jre\bin\server\) represents the different JVMs which you can use. The classic JVM refers to the non-JIT, interpreted JVM. The hotspot JVM uses Sun's HotSpot JIT technology, and is optimized for client applications. The server JVM is also a HotSpot-JIT JVM, but is optimized for server applications.

Note that the structure above varies according to the make and version of the JRE. For example, in Sun's JDK 1.2, the classic JVM refers to a JIT JVM licensed from Symantec. The Hotspot JVMs were only introduced in JDK 1.3. Similarly, the structure for IBM's JDK, or JDK from other vendors could be different.

Once you have copied the jre\ subdirectory to your application directory, you can generate an executable that will make use of that private JRE. Just specify the relative path to the desired JVM DLL file in NativeJ, and generate the executable. For example, if you specify jre\bin\hotspot\jvm.dll in the JVM DLL parameter box, it means you want to use the client-optimized HotSpot JVM for your application.

Finally, create an installer that will replicate the entire application directory to the user's machine. This is easily done with a modern installer maker by using the project wizard and specifying the root directory of the application to be bundled.


How NativeJ searches for a suitable JDK/JRE

When a NativeJ-generated executable starts up, the first thing it needs to do is to look for a suitable jvm.dll file to run the Java application.

If the JVM DLL parameter is specified, that will be the first place it looks. For example, if the JVM DLL parameter is jre\bin\client\jvm.dll, and the program directory is C:\Program Files\Tomcat, the executable will check if the file C:\Program Files\Tomcat\jre\bin\client\jvm.dll exists. If it does, then the Java application will be started using that file, no questions asked.

Next, the executable will look for a suitable JRE in the Windows registry at HKLM\Software\JavaSoft\Java Runtime Environment. The CurrentVersion value gives the location of the current JRE installed. For example, if the value is "1.4", the details for the current JRE will be available in HKLM\Software\JavaSoft\Java Runtime Environment\1.4\RuntimeLib.

If that fails (file not found, or version mismatch), the executable will iterate through all subkeys under HKLM\Software\JavaSoft\Java Runtime Environment to locate a suitable JRE. The same process is repeated for HKLM\Software\IBM\Java Runtime Environment to locate a JRE from IBM.

If none of the JREs are suitable, the executable will make an attempt to use any JDK installed on the system. It does so by first looking at the CurrentVersion value in HKLM\Software\JavaSoft\Java Developer Kit. Then it looks at the JavaHome value for the current JDK and try various locations for jvm.dll:

  • JVM DLL (if specified)
  • jre\bin\client\jvm.dll
  • jre\bin\server\jvm.dll
  • jre\bin\classic\jvm.dll

If that fails, it iterates through all the subkeys in HKLM\Software\JavaSoft\Java Developer Kit, and check each installed JDK. The same process is repeated for HKLM\Software\IBM\Java Developer Kit to locate a JDK from IBM.

If a suitable jvm.dll cannot be located after this comprehensive search process. the executable gives up and displays an error message.


Passing options to the Java runtime

For certain situations, you may need to pass some options to the JVM. For example, to increase the maximum amount of memory available to the JVM, we typically use:

java -ms64m -mx128m examples.Console

This means the initial memory available to the JVM is 64MB, while the maximum amount of memory available to the JVM is 128MB. This is frequently necessary when running complex server applications.

The typical options available in java.exe are as follows:

C:\java -h
Usage: java [-options] class [args...]
           (to execute a class)
   or  java -jar [-options] jarfile [args...]
           (to execute a jar file)

where options include:
    -client       to select the "client" VM
    -server       to select the "server" VM
    -hotspot      is a synonym for the "client" VM  [deprecated]
                  The default VM is client.

    -cp -classpath <directories and zip/jar files separated by ;>
                  set search path for application classes and resources
    -D<name>=<value>
                  set a system property
    -verbose[:class|gc|jni]
                  enable verbose output
    -version      print product version and exit
    -showversion  print product version and continue
    -? -help      print this help message
    -X            print help on non-standard options
    -ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  enable assertions
    -da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  disable assertions
    -esa | -enablesystemassertions
                  enable system assertions
    -dsa | -disablesystemassertions
                  disable system assertions

However, because NativeJ's executable operates at a lower level than java.exe, you cannot use the standard options such as -ms, - mx, -cp etc. Instead, you will need to use non-standard options prefixed by -X.

C:\java -X
    -Xmixed           mixed mode execution (default)
    -Xint             interpreted mode execution only
    -Xbootclasspath:  <directories and zip/jar files separated by ;>
                      set search path for bootstrap classes and resources
    -Xbootclasspath/a:<directories and zip/jar files separated by ;>
                      append to end of bootstrap class path
    -Xbootclasspath/p:<directories and zip/jar files separated by ;>
                      prepend in front of bootstrap class path
    -Xnoclassgc       disable class garbage collection
    -Xincgc           enable incremental garbage collection
    -Xloggc:<file>    log GC status to a file with time stamps
    -Xbatch           disable background compilation
    -Xms<size>        set initial Java heap size
    -Xmx<size>        set maximum Java heap size
    -Xss<size>        set java thread stack size
    -Xprof            output cpu profiling data
    -Xrunhprof[:help]|[:<option>=<value>, ...]
                      perform JVMPI heap, cpu, or monitor profiling
    -Xdebug           enable remote debugging
    -Xfuture          enable strictest checks, anticipating future default
    -Xrs              reduce use of OS signals by Java/VM
    -Xcheck:jni       perform additional checks for JNI functions

The -X options are non-standard and subject to change without notice.

Hence, to increase the maximum amount of memory available to an application under NativeJ, you need to specify -Xms64m -Xmx128m under the JVM options parameter box.

Since the -X options are non-standard options and vary across different makes and versions of JVMs, this approach works best if you are bundling a private JRE so that you can be sure that the -X options that you supply will work with the bundled JVM.


JAR files embedding

Embedding JAR files bloats the final executable significantly. The JAR files also need to be extracted when the executable is first run, which introduces an execution delay. As such, JAR files embedding is only recommended for smallish applications where the total size of the embedded JAR files is small.

Let's take a look at what happens when an executable with embedded JAR files is run. The executable will first check to see if the embedded JAR files have already been extracted. The target directory is <TEMP>\<APPCODE>. TEMP is typically c:\Documents and Settings\UserName\Local Settings\Temp. APPCODE is a unique hash value which is created from the product serial number and the application main class name. Hence, the target directory is guaranteed to be unique to applications with different main class names.

If a particular JAR file cannot be found, or if their file size or timestamp do not match, the embedded version will be extracted. Depending on the size of the JAR files, this could take considerable time and introduces a delay in the execution. Once the JAR files are extracted, the classpath is modified to point to these JAR files. Then the application starts.

When the executable is subsequently run, the extraction process does not take place. After a quick check to ensure that the JAR files are available and identical to the embedded ones, the application starts.


An alternative approach to classpath

If you are bundling a private JRE with your application, it may not be necessary for you to specify the .jar files your application uses in the Classpath parameter box.The JRE provides a repository in jre\lib\ext where these files can reside so that they can be automatically recognized and loaded by the runtime.

In the directory structure below, examples.jar has been moved to jre\lib\ext. Hence there is no longer any need to specify it in the Classpath parameter box.

approot\
  jre\
    bin\
      classic\
        jvm.dll
      hotspot\
        jvm.dll
      server\
        jvm.dll
    lib\
      ext\
        examples.jar
  console.exe


Implementing a generic start/stop mechanism for services

In Service.java, the main() method accepts two arguments - start and -stop. The -start argument activates a loop which continually logs the current date/time to a log file called service.log. On the other hand, the -stop argument simply sets a stop flag to true at line 35. When the main program loop detects the stop flag, it will terminate (line 23-27).

File: Service.java
1:  package examples;
2:
3:  import java.io.*;
4:  import java.util.*;
5:
6:  public class Service
7:  {
8:      static boolean stop = false;
9:      public static void main(String[] args) throws Exception
10:     {
11:         // Start the service
12:         if (args[0].equals("-start"))
13:         {
14:             while(true)
15:             {
16:                 // Append current date/time to log file
17:                 log("Current date/time is " + new Date());
18:
19:                 // Sleep for 5 secs
20:                 Thread.currentThread().sleep(5000);
21:
22:                 // Check for termination
23:                 if (stop)
24:                 {
25:                     log("Service stopped.");
26:                     break;
27:                 }
28:             }
29:         }
30:         else
31:         // Stop the service
32:         if (args[0].equals("-stop"))
33:         {
34:             // Set the termination flag
35:             stop = true;
36:         }
37:     }
38:
39:     /**
40:      * Log given string to file "service.log".
41:      */
42:     static void log(String msg) throws IOException
43:     {
44:         PrintWriter pw = new PrintWriter(
45:             new FileWriter("service.log", true));
46:         pw.println(msg);
47:         pw.close();
48:     }
49: }

This approach works with NativeJ-generated executables, but it will not work when moved to another platform such as Solaris, where shell scripts are the norm. This is because the -start and -stop arguments will be passed to different JVM instances, which means they will be executing in different address space.

A more platform-independent way of terminating a Java program that is meant to run continuously as a service (Win32) or daemon (Unix) is to implement some form of IPC (inter-process communication). An example is given in Service2.java, which uses IP datagrams to communicate the intent for program termination.

File: Service2.java
1:  package examples;
2:
3:  import java.io.*;
4:  import java.net.*;
5:  import java.util.*;
6:
7:  public class Service2
8:  {
9:      /**
10:      * This is the port over which the termination signal is sent.
11:      */
12:     private final static int port = 5678;
13:
14:     /**
15:      * This is the message to be sent to signal termination.
16:      */
17:     private final static String terminator = "QUIT";
19:
20:     /**
21:      * The main() function accepts one single parameter:
22:      * "start" or "stop".
23:      * The first parameter starts the date/time logging service,
24:      * while the second parameter stops the service.
25:      */
26:     public static void main(String[] args) throws Exception
27:     {
28:         // Start the service
29:         if (args[0].equals("start"))
30:         {
31:             try
32:             {
33:                 // Run the termination listener thread
34:                 TerminationListener t = new TerminationListener(
35:                     port, terminator, Thread.currentThread());
36:                 t.start();
37:
38:                 // Start the logging service
39:                 while(true)
40:                 {
41:                     // Append current date/time to log file
42:                     log("Current date/time is " + new Date());
43:
44:                     // Sleep for 5 secs
45:                     Thread.currentThread().sleep(5000);
46:                 }
47:             }
48:             catch(InterruptedException e)
49:             {
50:                 // Exit when thread is interrupted.
51:                 log("Service stopped.");
52:             }
53:         }
54:         else
55:         // Stop the service
56:         if (args[0].equals("stop"))
57:         {
58:             try
59:             {
60:                 // Send the termination message
61:                 DatagramSocket socket = new DatagramSocket();
62:                 DatagramPacket packet = new DatagramPacket(
63:                     terminator.getBytes(), terminator.length(),
64:                     InetAddress.getLocalHost(), port);
65:                 socket.send(packet);
66:             }
67:             catch(Exception e)
68:             {
69:                 e.printStackTrace();
70:             }
71:         }
72:     }
73:
74:     /**
75:      * Log given string to file "service.log".
76:      */
77:     static void log(String msg) throws IOException
78:     {
79:         PrintWriter pw = new PrintWriter(
80:             new FileWriter("service.log", true));
81:         pw.println(msg);
82:         pw.close();
83:     }
84: }
85:
86: /**
87:  * This is a thread that will listen for the termination message
88:  * over the designated port, then interrupt the parent thread.
89:  */
90: class TerminationListener extends Thread
91: {
92:     Thread parent;
93:     int port;
94:     String terminator;
95:
96:     /**
97:      * Set this thread to daemon mode so that if for some reason
98:      * the main thread exists, this thread will not prevent the
99:      * JVM from terminating.
100:     */
101:    public TerminationListener(
102:        int port, String terminator, Thread parent)
103:    {
104:        setDaemon(true);
105:        this.port = port;
106:        this.terminator = terminator;
107:        this.parent = parent;
108:    }
109:
110:    /**
111:     * Listen for the termination signal over the designated port.
112:     */
113:    public void run()
114:    {
115:        try
116:        {
117:            // Setup datagram socket
118:            DatagramSocket socket = new DatagramSocket(port);
119:            DatagramPacket packet = new DatagramPacket(
120:                new byte[terminator.length()], terminator.length());
121:
122:            // Stop only when we have received the termination message
123:            while(true)
124:            {
125:                // Wait for a message
126:                socket.receive(packet);
127:                String msg = new String(packet.getData());
128:
129:                // Make sure the message is coming from the same
130:                // machine. This is included for additional security
131:                // so that the program cannot be terminated from an
132:                // external machine).
133:                if (!packet.getAddress().equals(
134:                    InetAddress.getLocalHost()))
135:                        continue;
136:
137:                // Make sure the message is the termination message
138:                if (!msg.equals(terminator)) continue;
139:
140:                // Interrupt parent thread
141:                parent.interrupt();
142:
143:                // Terminate this thread
144:                break;
145:            }
146:        }
147:        catch(Exception e)
148:        {
149:        }
150:    }
151:}

A TerminationListener class is defined in line 90, that runs in the background and waits for an IP datagram from a predefined port (default: 5678) on the local machine. This is instantiated and started in lines 34-36 when the -start argument is used. Let's say this runs in JVM instance #1.

When the -stop argument is issued, this runs in JVM instance #2. The instructions in lines 61-65 will send out an IP datagram containing the message "QUIT". This will be routed over to the TerminationListener in JVM instance #1, logging activities will stop, and JVM instance #1 will terminate. Similarly, once JVM instance #2 has sent out the "QUIT" message, it will also terminate.

This approach to graceful termination of a server app will work under NativeJ, as well as all Java-enabled platforms with TCP/IP capability. Hence, you will have one set of source codes that can work with both NativeJ-generated Win32 executables, as well as on other platforms using more traditional batch files, shell scripts, or just plain "java <class>".


NativeJ 1.0.x project files

The project file extension in NativeJ 1.0 is .prj. In NativeJ 2.0 and above, the project file extension is changed to .njp, and file association capabilities are implemented so that you can launch a project file by double-clicking on it.

Despite the change in extension, the project file format remains the same. Hence you can simply rename the extension of old .prj files to .njp, and launch them in NativeJ 2.0 and above.


Copyright and license

All copyrights to NativeJ are exclusively owned by DobySoft.

The user is granted a non-exclusive license to use NativeJ on one computer (i.e. a single CPU), for any legal purpose, at a time. The NativeJ software may not be rented or leased, but may be permanently transferred if the person receiving it agrees to terms of this license. If the software is an update, the transfer must include the update and all previous versions.

NativeJ is distributed "as is". No warranty of any kind is expressed or implied. You use at your own risk. DobySoft will not be liable for data loss, damages, loss of profits or any other kind of loss while using or misusing this software. All rights not expressly granted here are reserved by DobySoft.

Installing and using NativeJ signifies acceptance of these terms and conditions of the license. If you do not agree with the terms of this license, you must remove NativeJ files from your storage devices and cease to use the product.


Support and updates

For the latest news and updates about NativeJ, please visit the product website at: http://www.dobysoft.com/products/nativej/.


Ordering information

The trial version allows you to test all functions of NativeJ. However, the executables generated will display a short trial message on startup until you register the software.

To enjoy the full functionality of NativeJ, please register the software at: http://www.dobysoft.com/products/nativej/purchase.html.


Version history

Date Version Changes
14/04/2005 4.5.7
  • Previously, if an environment variable involved in variable substitution contains a very long string (> 260 characters), the executable will crash. This has been fixed.
15/03/2005 4.5.6
  • Updated JVM options verification algorithm to avoid flagging certain valid options as invalid.
19/01/2005 4.5.5
  • Generated service will exit when user logs out. This has been fixed.
  • Updated copyright notice.
23/12/2004 4.5.4
  • Improved registration code verification logic.
14/12/2004 4.5.3
  • The executables generated by V4.5.0 to V4.5.2 broke compatibility with Win9x/ME. This has been fixed.
02/12/2004 4.5.2
  • Executable path is now reflected in nativej.exe.path instead of java.exe.path to avoid potential compatibility issues with Sun's properties.
  • nativejc now returns 0 on success, or -1 on failure to better integrate with third-party build tools.
  • nativejc now supports verbose mode via the -v switch.
25/11/2004 4.5.1
  • Executable path is now reflected in the java.exe.path property.
  • Console window was not displayed for console services configured to interact with the desktop. This has been fixed.
  • Ctrl-Break did not generate thread dump for console services configured to interact with the desktop. This has been fixed.
  • If the splash screen was configured to hide when application displayed a window, and a JVM error occurred, the error detail window was not brought to the foreground. This has been fixed.
05/11/2004 4.5.0
  • Added support for JDK/JRE V5.0 (JVM V1.5).
  • Added extra syntax checks for JVM options, classpath and embedded JAR files during entry.
  • Added option to always delete embedded JAR files when EXE terminates.
  • Added redirection of stdout/stderr to popup message box (for GUI applications) or event log (for Win32 services).
  • Added option to allow Win32 services to interact with desktop.
08/09/2004 4.2.3
  • Previously, if the total length of the classpath is longer than 1024 characters, the generated executable will fail when run. This has been fixed.
29/08/2004 4.2.2
  • Previously, an executable with embedded jar files will crash when a second instance is launched. This has been fixed.
11/08/2004 4.2.1
  • Added up/down re-ordering buttons in the JVM search order window.
02/08/2004 4.2.0
  • Added finer control of JVM search order.
  • Added button to run executable directly after EXE generation.
  • Output version-related warning messages during EXE generation.
  • Output extraction location of embedded JAR files during EXE generation.
12/07/2004 4.1.1
  • Previously, when the second instance of an executable with embedded jar files is run, an error message will be displayed (although the program will continue to run). This has been fixed.
05/07/2004 4.1.0
  • Generated executables have been enhanced to display startup/operational errors from the JVM such as insufficient memory, hotspot errors etc.
  • System.exit() will now be trapped and handled accordingly, so there is no need to avoid them in your Java code. Recommendations for avoiding System.exit() have also been removed from the help file.
29/05/2004 4.0.2
  • Previously, NativeJ may interact incorrectly with a native Java splash screen. This has been fixed.
  • Added frequently asked questions to help file.
03/05/2004 4.0.1
  • Previously, if a referenced environment variable is not present during substitution, the generated executable will crash. This has been fixed.
26/04/2004 4.0.0
  • Added new registration system.
  • Added XP visual style and icons.
  • Added "New Project Wizard" to simplify project creation for new users.
  • Added ability to embed JAR/ZIP files in generated executables.
  • Added ability to specify initial process priority.
  • Added ability to specify service dependencies.
  • Added ability to redirect stdout/stderr to external log files.
  • Added compression of generated executables.
  • Required fields are now highlighted in red.
  • Project icon is no longer required. If none is specified, the default icon is used.
15/03/2004 3.6.4
  • The size of the "JVM DLL" and "JVM options" text fields were wrong, resulting in the apparent inability to move to the end of the text field. This has been fixed.
29/02/2004 3.6.3
  • In this release, generated executables no longer verify the existence of each directory/file in the classpath. This conforms to the behaviour of the java.exe launcher, and allows for optional directories/files to be specified in the classpath.
09/02/2004 3.6.2
  • Fixed issue in classpath environment variable substitution when the variable contains leading and ending quotes.
28/07/2003 3.6.1
  • Fixed tab order for some panels.
15/07/2003 3.6.0
  • Added support for multiple private Java runtimes.
  • The working directory can now be set to the current directory for programs which must perform processing on files in the directory where it is started.
01/07/2003 3.5.1
  • Added AppOptions parameter to the application configuration file. This parameter allows you to specify the arguments to pass to the Java application at runtime.
23/06/2003 3.5.0
  • Changed shortcut for "Exit" command from Ctrl-X to Ctrl-E because Ctrl-X is used for text editing.
  • Updated help file to make it clearer on what we should do when copying the JRE, and how the final directory structure should look like.
  • Added more search sequences for JVM, so now you can specify to use the bundled JRE only if a suitable JRE is not already installed on the target machine. This is useful if the bundled JRE is located on a slower medium, so as the CDROM.
  • Added ability to look for private JVM DLL and classpath modules relative to the working directory. Previously, search for the private JVM DLL and classpath modules are always relative to the executable directory.
  • Added application configuration file support so that certain parameter values are resolved only when the executable is run. Currently only JVM options is supported in the configuration file.
09/06/2003 3.4.3
  • When a console program is run as a service and allowed to interact with the desktop, the console output is not enabled. This has been fixed.
  • When a working directory is specified, the "user.dir" property is not updated. This has been fixed.
  • When the splash screen is configured to be removed as soon as the Java application displays its first window, it does so even when the window is not completely displayed on screen. This has been fixed.
18/05/2003 3.4.2
  • The "Allow multiple instances" parameter is inverted i.e. when checked, it denies multiple instances and vice-versa. This has been fixed.
  • Splash screen feature is only enabled in registered versions. This has been fixed.
  • Splash screen preview is not refreshed correctly under certain situations. This has been fixed.
  • When the splash screen bitmap is larger than the preview control, the image will now be scaled and displayed proportionally within the preview control.
17/05/2003 3.4.1
  • When changing certain parameters, the changed status of the project is not updated. This has been fixed.
16/05/2003 3.4.0
  • Added ability to configure application working directory.
  • Added ability to specify startup type and description for services.
  • Added ability to call System.exit() to terminate services.
06/05/2003 3.3.0
  • You can now specify the search order for a suitable JVM. By default, NativeJ searches for a suitable JRE, followed by a suitable JDK. You can change the search order to look for the JDK first, then JRE. You can also restrict the search to the JRE or JDK only.
  • Provision is now made for environment variable substitution in the JVM options and classpath. All tokens of the form %name% are substituted with the value of the corresponding environment variable found on the target machine. A special case is %JAVA_HOME%, which will always be substituted with the actual JDK/JRE base directory on the target machine.
30/04/2003 3.2.0
  • Besides JREs, the search for a suitable JVM is now extended to JDKs installed on the target machine as well.
  • The help file is updated to include the JVM search strategy and version history.
24/04/2003 3.1.0
  • Besides searching for the current version of JRE (listed in HKLM\Software\JavaSoft\Java Runtime Environment\CurrentVersion), the generated EXE now automatically searches for all suitable JREs installed on the target machine (listed under HKLM\Software\JavaSoft\Java Runtime Environment\1.x).
10/04/2003 3.0.0
  • Added command-line version of NativeJ to integrate better into project build processes.
  • Added native splash screen support for GUI apps.
  • Major facelift of the user interface for a more modern look-and-feel.
15/03/2003 2.0.2
  • Under certain situations, when the help menu item or button is clicked, the help file is not displayed. This happens when the current directory is no longer the program directory eg. when you open a project file or icon file. It has been fixed.
07/03/2003 2.0.1
  • There is an off-by-one error in new projects such that the last message (ID 19) is missing. This error does not apply to existing projects. It has been fixed.
  • A related error is that when saving new projects, an "Index out of bounds" exception occurs. This error does not apply to existing projects. It has been fixed.
  • When running NativeJ in demo mode, the EXE generated will encounter a "Division by zero" exception under some circumstances. This has been fixed.
27/02/2003 2.0.0
  • This version is now branded under DobySoft instead of CTech Software.
  • Added new registration system so that license key can be sent out faster via automated system.
  • Changed project extension from .prj to .njp, and added project file association logic.
  • Added drag-and-drop support for project files.
  • Added toolbar.
  • Added memory of recent projects.
  • Added ability to customize/localize strings and messages in generated executables.
  • Added ability to modify service install/uninstall commands.
  • Added recursive search for .jar and .zip files within classpath directories.
  • Documentation is now in .chm format.
11/01/2003 1.0.7
  • If executable runs as Win32 service, and the "-Xrs" option is not specified for the JVM, logging out will cause the service to terminate. This has been fixed.
14/10/2002 1.0.6
  • This version supports two license types: standard and professional.
21/08/2002 1.0.5
  • Generated executables had problems with Sun JDK 1.3.0 in some cases. This has been fixed.
  • Setting the required JDK version field to > 1.2 causes generated executables to fail to run. This has been fixed.
23/06/2002 1.0.4
  • Center window on screen upon startup.
17/06/2002 1.0.3
  • Fixed a service-related bug in the generated executable. Without this fix, some Java programs which do not require a startup argument may not be able to run as a service.
09/06/2002 1.0.2
  • Fixed a minor bug with the About dialog box.
07/06/2002 1.0.1
  • During generation of executable, if icon file is invalid, display a more meaningful message.
03/06/2002 1.0.0
  • First release.